#include "tcpclient.h"
#include "machinemgr.h"

#include <QFutureWatcher>
#include <QtConcurrent>

uint16_t CRC_Check(const uint8_t *CRC_Ptr,uint8_t LEN)
{
    uint16_t CRC_Value = 0;
    uint8_t  i         = 0;
    uint8_t  j         = 0;

    CRC_Value = 0xffff;
    for(i=0;i<LEN;i++)  //LEN为数组长度
    {
        CRC_Value ^= *(CRC_Ptr+i);
        for(j=0;j<8;j++)
        {
            if(CRC_Value & 0x00001)
                CRC_Value = (CRC_Value >> 1) ^ 0xA001;
            else
                CRC_Value = (CRC_Value >> 1);
        }
    }
    CRC_Value = ((CRC_Value >> 8) +  (CRC_Value << 8)); //交换高低字节

    return CRC_Value;
}

std::string unsignedCharToHex(unsigned char c) {
    const char hexChars[] = "0123456789ABCDEF";
    std::string result;
    result += hexChars[(c >> 4) & 0x0F];  // 高4位
    result += hexChars[c & 0x0F];          // 低4位
    return result;
}

TcpClient::TcpClient()
{
    timer = new QTimer(this);


    m_readParam = new  MachineReadParam();
    m_writeParam = new MachineWirteParam();
    m_writeParam->m_enable = true;



    connect(this, &QTcpSocket::connected, this, &TcpClient::onConnected);
    //connect(this, &QTcpSocket::readyRead, this, &TcpClient::onReadyRead);
   // connect(this, qOverload<QAbstractSocket::SocketError>(&QTcpSocket::error), this, &TcpClient::onError);//qOverload是和哪里重载了？
}

TcpClient::~TcpClient()
{
    delete m_readParam;
    delete m_writeParam;

}

MachineReadParam *TcpClient::getReadParam()
{
    //功能码0x03(读多路寄存器输入),寄存器起始地址0x0001,(占用40002,40003,40004,40005),读4个字的数据
    // 01 03 00 01 00 04 CRC CRC
    unsigned char arr[8] = {0x01, 0x03, 0x00, 0x01, 0x00, 0x04};
    uint16_t crc =CRC_Check(arr,6);
    arr[6] = crc >> 8;
    arr[7] = crc << 8 >>8;

    QByteArray qArr((char *)arr, sizeof(arr)/sizeof(unsigned char));
    QByteArray rsp = sendData(qArr);

    const unsigned char *rspChar =(unsigned char*) rsp.constData();
    int size = rsp.size();
    if(size < 2 || !rspChar)
    {
        return NULL;
    }

    string str;
    for(auto i : rsp)
    {
        str += unsignedCharToHex(i) + " ";
    }
    qDebug() << " getWriteParam rsp:" << str.c_str();

    if(rspChar[0] != arr[0] || rspChar[1] != arr[1])
    {
        qWarning() << " getWriteParam rsp err:" << unsignedCharToHex(rspChar[0]).c_str();
        return NULL;
    }

    if(size != 13)
    {
        qWarning() << " getWriteParam rsp err:" << unsignedCharToHex(rspChar[0]).c_str();
        return NULL;
    }

    uint16_t rspCrc =CRC_Check(rspChar,11);
    if( rspChar[11] != (unsigned char)(rspCrc >> 8) || rspChar[12] != (unsigned char)(rspCrc << 8 >>8))
    {
        qWarning() << " getWriteParam rsp crc err:" << unsignedCharToHex(rspChar[1]).c_str();
        return NULL;
    }

    //数据1
    m_readParam->m_fatalWarn =  rspChar[3] & 1;
    m_readParam->m_bLoseNet =  rspChar[3]>>2 & 1;

    //心跳是什么意思?
    m_readParam->m_bStart = rspChar[4] & 1;

    m_readParam->m_direction =(Direction)rspChar[6];

    m_readParam->m_leftSpeed = rspChar[7] * 256 + rspChar[8];
    m_readParam->m_rightSpeed = rspChar[9] *256 + rspChar[10];
    qDebug()<< " loseNet:" << m_readParam->m_bLoseNet <<
               " fatalWarn:" << m_readParam->m_fatalWarn <<
               " bStart:" << m_readParam->m_bStart <<
               " direction:" << m_readParam->m_direction <<
               " leftSpeed:" << m_readParam->m_leftSpeed <<
               " rightSpeed:" << m_readParam->m_rightSpeed;

    emitReadParam(*m_readParam);
    return m_readParam;
}

MachineWirteParam *TcpClient::getWriteParam()
{
    return m_writeParam;
}

bool TcpClient::execWriteParam()
{
    //目前版本只支持写多路寄存器，所以需要需要所有设置项
    //功能码0x10(写多路寄存器),寄存器起始地址0x0005,(占用40006,40007,40008),写3个字的数据
    //01 10 00 05 00 03 06

    unsigned char arr[15] ={0x01, 0x10, 0x00,0x05,0x00,0x03,0x06};

    //word0 H
    m_writeParam->m_enable = true;//should always true
    m_writeParam->m_enable ? arr[7] = (arr[7] | 1) : arr[7] = (arr[7] & ~1);
    m_writeParam->m_lightWarn ?arr[7] = (arr[7] | (1<< 1)) : arr[7] =(arr[7] & ~(1 <<1));
    m_writeParam->m_fatalWarn ? arr[7] = (arr[7] | (1<< 2)) : arr[7] =(arr[7] & ~(1 <<2));

    //word0 L
    arr[8] = m_writeParam->m_direction;

    //word 1
    uint16_t leftSpeed = m_writeParam->m_leftSpeed;
    arr[9] = leftSpeed >> 8;
    arr[10] = leftSpeed << 8 >>8;

    //word 2
    uint16_t rightSpeed = m_writeParam->m_rightSpeed;
    arr[11] = rightSpeed >> 8;
    arr[12] = rightSpeed << 8 >>8;

    uint16_t crc =CRC_Check(arr,13);
    arr[13] = crc >> 8;
    arr[14] = crc << 8 >>8;

    std::string str;
    for(auto i : arr)
    {
        str += unsignedCharToHex(i) + " ";
    }

    QByteArray qArr((char *)arr, sizeof(arr)/sizeof(unsigned char));

    qDebug() << " writMulti req:" << str.c_str();

    QByteArray rsp = syncSendData(qArr);

    if(rsp.isEmpty() || rsp.size() < 2)
    {
        return false;
    }

    const char *rspChar = rsp.constData();
    if(rspChar[0] != 0x01 && rspChar[1] != 0x10 )
    {
        qWarning() << " writMulti rsp err:" << unsignedCharToHex(rspChar[1]).c_str();
    }

    return true;
}

QByteArray TcpClient::syncSendData(const QByteArray &data){
    write(data);
    waitForBytesWritten(); // 等待数据发送完毕
    if(waitForReadyRead(2000)) // 等待响应
    {
        QByteArray arr = readAll();
        qDebug() << "sendData recive:" <<  arr.toHex();
        return arr;
    }

     qDebug() << "sendData recive timeout";
     return QByteArray();
}

 QFuture<QByteArray> TcpClient::sendData(const QByteArray &data)
{
    return QtConcurrent::run([=]() {

        write(data);
        waitForBytesWritten(); // 等待数据发送完毕
        if(waitForReadyRead(1000)) // 等待响应
        {
            QByteArray arr = readAll();
            qDebug() << "sendData recive:" <<  arr.toHex();
            return arr;
        }

         qDebug() << "sendData recive timeout";
         return QByteArray();

    });
}

void TcpClient::onConnected()
{
    qDebug() << "Connected to server";
    timer->stop();

    ClientMgr::getInstance().add(this);

    emit connected();
    //write("Hello Server!"); // 发送数据到服务器
    timer->stop();
    timer->disconnect();
    connect(timer, &QTimer::timeout, this,  &TcpClient::getReadParam);
    //定时读取参数--心跳防止断开
    timer->start(1000);
    //reset
    m_writeParam->m_enable = 1;

}

void TcpClient::onError(QAbstractSocket::SocketError socketError)
{
    qWarning() << "Error:" << errorString();
    emit error(socketError);

    if(timer)
    {
        timer->stop();
    }
}
